//
// Created by glyn on 2024/3/22.
//

#ifndef GTLV_H
#define GTLV_H
#include "basetype.h"
#include <vector>
#include <string>
#define OBJTLV 0 ///TLV容器的类型

/**--------------只对TL转换  V不转换  --------------**/
#define BIGENDIAN 0 ///大端 big-endian
#define LITTLEENDIAN 1 ///小端 little-endian

#define ENDIANNESS BIGENDIAN ///序列化字节顺序

class gtlv {
    public:
    gtlv():mType(OBJTLV)
    {
        mLen =0;
    }

    gtlv(int32_t type):mType(type)
    {
        mLen =0;
    }
    gtlv(int32_t type, bool value):mType(type)
    {
        Initialize(&value,sizeof(value));
    }
    gtlv(int32_t type, int8_t value):mType(type)
    {
        Initialize(&value,sizeof(value));
    }
    gtlv(int32_t type, int16_t value):mType(type)
    {
        Initialize(&value,sizeof(value));
    }
    gtlv(int32_t type, int32_t value):mType(type)
    {
        Initialize(&value,sizeof(value));
    }
    gtlv(int32_t type, int64_t value):mType(type)
    {
        Initialize(&value,sizeof(value));
    }
    gtlv(int32_t type, uint8_t value):mType(type)
    {
        Initialize(&value,sizeof(value));
    }
    gtlv(int32_t type, uint16_t value):mType(type)
    {
        Initialize(&value,sizeof(value));
    }
    gtlv(int32_t type, uint32_t value):mType(type)
    {
        Initialize(&value,sizeof(value));
    }
    gtlv(int32_t type, uint64_t value):mType(type)
    {
        Initialize(&value,sizeof(value));
    }
    gtlv(int32_t type, float value):mType(type)
    {
        Initialize(&value,sizeof(value));
    }
    gtlv(int32_t type, double value):mType(type)
    {
        Initialize(&value,sizeof(value));
    }
    gtlv(int32_t type, char* value,int32_t len):mType(type)
    {
        Initialize(value,len);
    }
    gtlv(int32_t type, std::string value):mType(type)
    {
        Initialize(value.c_str(),value.size());
    }

    gtlv(int32_t type, uint8_t *value, int32_t len):mType(type)
    {
        Initialize(value,len);
    }



    gtlv(int32_t type, const gtlv& value):mType(type)
    {
        mTlv.push_back(value);
        mLen += value.mLen;
    }

    /**
     * 添加tlv
     * @param value tlv
     */
    void addtlv(gtlv& value){
        mTlv.push_back(value);
        mLen += value.mLen;
    }

    ~gtlv(){
        mValue.clear();
        mTlv.clear();
    }

    bool getbool() const
    {
        bool ret= *((bool *)mValue.data());
        return ret;
    }

    int8_t getint8() const
    {
        int8_t ret= *((int8_t *)mValue.data());
        return ret;
    }

    int16_t getint16() const
    {
        int16_t ret= *((int16_t *)mValue.data());
        return ret;
    }
    int32_t getint32() const
    {
        int32_t ret= *((int32_t *)mValue.data());
        return ret;
    }
    int64_t getint64() const
    {
        int64_t ret= *((int64_t *)mValue.data());
        return ret;
    }
    uint8_t getuint8() const
    {
        uint8_t ret= *((uint8_t *)mValue.data());
        return ret;
    }
    uint16_t getuint16() const
    {
        uint16_t ret= *((uint16_t *)mValue.data());
        return ret;
    }

    uint32_t getuint32() const
    {
        uint32_t ret= *((uint32_t *)mValue.data());
        return ret;
    }

    uint64_t getuint64() const
    {
        uint64_t ret= *((uint64_t *)mValue.data());
        return ret;
    }

    float getfloat() const
    {
        float ret= *((float *)mValue.data());
        return ret;
    }

    double getdouble() const
    {
        double ret= *((double *)mValue.data());
        return ret;
    }

    std::string getstring()
    {
        std::string ret((char *)mValue.data(),mValue.size());
        return ret;
    }

    int32_t getstr(char *str)
    {

        memcpy(str,mValue.data(),mValue.size());
        return mValue.size();
    }

    int32_t getstr(uint8_t *str)
    {

        memcpy(str,mValue.data(),mValue.size());
        return mValue.size();
    }

    std::vector<gtlv>& tlvObj(){

        return mTlv;
    }

    void Initialize(const void *value, int32_t length )
    {
        mLen = length;

        mValue.assign((uint8_t *) value,(uint8_t *) value+length);

    }

    /**
     * 获取类型
     * @return 类型
     */
    uint32_t getType(){
        return mType;
    }

    /**
     * 获取长度
     * @return 长度
     */
    uint32_t getLen(){
        int32_t len=0;

        if(mType == OBJTLV)
        {
            for (auto it : mTlv)
            {
                len =len + it.getLen();
            }

            len = len + 4 + 4;

        }else{
            len = mLen + 4 + 4;

        }


        return len;
    }

    /**
     * 本地字节顺序转换为网络字节顺序
     * @param out 输出
     * @param in 输入
     * @param len 转换长度 单位byte
     */
    inline void hostToNetCpy(void * out,void* in,int32_t len){
        for (int i = 0; i < len; ++i) {
            ((char *)out)[i] = ((char *)in)[len - i - 1];
        }
    }

    /**
     * 网络字节顺序转换为本地字节顺序
     * @param out 输出
     * @param in 输入
     * @param len 转换长度 单位byte
     */
    inline void netToHostCpy(void * out,void* in,int32_t len){
        for (int i = 0; i < len; ++i) {
            ((char *)out)[i] = ((char *)in)[len - i - 1];
        }
    }

    /**
     * vlt容器序列化
     * @param data 输出
     * @param offset 偏移量，默认为0
     * @return
     */
    int32_t serialization(void * data,int32_t offset = 0){

        int32_t len=0;

        if(ENDIANNESS == BIGENDIAN)
        {

            hostToNetCpy(((char *)data)+offset+len,&mType,sizeof(mType));

            len +=sizeof(mType);

            if(mType == OBJTLV)
            {
                mLen = getLen() - 8;
                hostToNetCpy(((char *)data)+offset+len,&mLen,sizeof(mLen));
                len +=sizeof(mLen);

                for (auto it : mTlv)
                {
                    auto itemLen= it.serialization(data,offset+len);
                    len +=itemLen;
                }

            }else{
                hostToNetCpy(((char *)data)+offset+len,&mLen,sizeof(mLen));
                len +=sizeof(mLen);

                memcpy(((char *)data)+offset+len,mValue.data(),mValue.size());

                len +=mLen;
            }

        }else{
            memcpy(((char *)data)+offset+len,&mType,sizeof(mType));
            len +=sizeof(mType);

            if(mType == OBJTLV)
            {
                mLen = getLen() - 8;
                memcpy(((char *)data)+offset+len,&mLen,sizeof(mLen));
                len +=sizeof(mLen);

                for (auto it : mTlv)
                {
                    auto itemLen= it.serialization(data,offset+len);
                    len +=itemLen;
                }

            }else{
                memcpy(((char *)data)+offset+len,&mLen,sizeof(mLen));
                len +=sizeof(mLen);

                memcpy(((char *)data)+offset+len,mValue.data(),mValue.size());

                len +=mLen;
            }

        }

        return len;

    }

    /**
     * vlt容器反序列化
     * @param data 输入
     * @param offset 偏移量，默认为0
     * @return
     */
    int32_t deserialization(void * data,int32_t offset = 0){
        int32_t len=0;
        if(ENDIANNESS == BIGENDIAN)
        {
            //读取类型
            netToHostCpy(&mType,((char *)data)+offset+len,sizeof(mType));
            len +=sizeof(mType);
            //读取长度
            netToHostCpy(&mLen,((char *)data)+offset+len,sizeof(mLen));
            len +=sizeof(mLen);
        }else{
            //读取类型
            memcpy(&mType,((char *)data)+offset+len,sizeof(mType));
            len +=sizeof(mType);
            //读取长度
            memcpy(&mLen,((char *)data)+offset+len,sizeof(mLen));
            len +=sizeof(mLen);

        }


        //判断是否是TLV集合
        if(mType == OBJTLV) {

            //TLV集合长度和记录
            int32_t iobj = 0;

            while (iobj < mLen) {
                gtlv item;

                auto itemLen= item.deserialization(data,offset+len);

                len = len + itemLen;

                iobj = iobj + itemLen;

                mTlv.push_back(item);

            }

        }else{
            mValue.clear();

            //加载数据
            mValue.assign((((char *)data)+offset+len),(((char *)data)+offset+len+mLen));
            len +=mLen;
        }

        return len;
    }

    private:

    uint32_t mType=0;
    uint32_t mLen=0;
    std::vector<uint8_t> mValue;
    std::vector<gtlv> mTlv;
};


#endif //GTLV_H
